﻿#include "MeasureView/MeasureAlgorithm.h"

#define M_PI 3.14159265358979323846

namespace Qly
{
bool PolygonMeasure::buildByPoints(QVector<QPointF> p)
{
    m_points = p;
    return computeArea();
}

bool PolygonMeasure::computeArea()
{
    int N = m_points.size();
    if(N < 2)
    {
        return false;
    }
    m_area = 0;
    for( int i = 0; i < N-1; i++ )
    {
        m_area += (m_points[i].x() * m_points[i+1].y() - m_points[i].y() * m_points[i+1].x())/2.0;

    }
    m_area += (m_points[N - 1].x() * m_points[0].y() - m_points[N-1].y() * m_points[0].x())/2.0;
    m_area = fabs(m_area);
    return true;
}

bool PolygonMeasure::buildByPoints(QVector<QPoint> p)
{
    m_points.clear();
    QVectorIterator<QPoint> i(p);
    while (i.hasNext())
    {
        m_points.push_back(i.next());
    }
    return computeArea();
}

bool AngleMeasure::buildBy3Points(QPoint p1, QPoint p2, QPoint p3)
{
    QPointF t1(p1), t2(p2), t3(p3);
    return buildBy3Points(t1, t2, t3);
}

bool AngleMeasure::buildBy3Points(QPointF p1, QPointF p2, QPointF p3)
{
    m_points[0] = p1;
    m_points[1] = p2;
    m_points[2] = p3;

    double y1 = m_points[0].y() - m_points[1].y();
    double x1 = m_points[0].x() - m_points[1].x();
    double y2 = m_points[2].y() - m_points[1].y();
    double x2 = m_points[2].x() - m_points[1].x();
    double y3 = m_points[0].y() - m_points[2].y();
    double x3 = m_points[0].x() - m_points[2].x();
    double b = hypot(y1, x1);
    double c = hypot(y2, x2);
    double a = hypot(y3, x3);
    m_theta = acos( ( b * b + c * c - a * a  )/ ( 2 * b * c ));
    m_degree = m_theta * 180.0 / M_PI;
    return true;
}

bool CircleMeasure::buildBy3Points(QPoint p1, QPoint p2, QPoint p3)
{
    QPointF t1(p1), t2(p2), t3(p3);
    return buildBy3Points(t1, t2, t3);
}

bool CircleMeasure::buildBy3Points(QPointF p1, QPointF p2, QPointF p3)
{
    m_points[0] = p1;
    m_points[1] = p2;
    m_points[2] = p3;
    double x[4], y[4];
    for(int i = 0; i < 3; i++)
    {
        x[i + 1] = m_points[i].x();
        y[i + 1] = m_points[i].y();
    }

    double a = x[1] - x[2];
    double b = y[1] - y[2];
    double c = x[1] - x[3];
    double d = y[1] - y[3];
    double e = ((x[1] * x[1] - x[2] * x[2]) + (y[1] * y[1] - y[2] * y[2])) / 2.0;
    double f = ((x[1] * x[1] - x[3] * x[3]) + (y[1] * y[1] - y[3] * y[3])) / 2.0;
    double det = b * c - a * d;
    if( fabs(det) < 1e-5)
    {
        m_radius = -1;
        m_centre = QPointF(0, 0);
        return false;
    }

    x[0] = -(d * e - b * f) / det;
    y[0] = -(a * f - c * e) / det;
    m_radius = hypot(x[1] - x[0], y[1] - y[0]);
    m_centre = QPointF(x[0], y[0]);

    for(int i = 0; i < 3; i++)
    {
        double dx = x[i + 1] - x[0];
        double dy = - y[i + 1] + y[0];
        m_theta[i] = atan2(dy, dx);
    }

    m_det_theta[0] = m_theta[1] - m_theta[0];
    m_det_theta[1] = m_theta[2] - m_theta[0];
    if(det > 0)
    {
        m_rotateDir = -1;
        if(m_theta[1] < m_theta[0]) m_det_theta[0] += 2 * M_PI;
        if(m_theta[2] < m_theta[0]) m_det_theta[1] += 2 * M_PI;
    }
    else
    {
        m_rotateDir = 1;
        if(m_theta[1] > m_theta[0]) m_det_theta[0] += 2 * M_PI;
        if(m_theta[2] > m_theta[0]) m_det_theta[1] += 2 * M_PI;
    }
    m_rectangle = QRectF(m_centre.x() - m_radius, m_centre.y() - m_radius, 2 * m_radius, 2 * m_radius);
    return true;
}

bool CircleMeasure::buildByCentreRadius(QPointF centre, double radius)
{
    m_centre = centre;
    m_radius = radius;
    m_rectangle = QRectF(m_centre.x() - m_radius, m_centre.y() - m_radius, 2 * m_radius, 2 * m_radius);
    return true;
}

bool CircleMeasure::buildByCentrePoint(QPointF centre, QPointF p)
{
    m_centre = centre;
    QPointF pt = p - m_centre;
    m_radius = hypot(pt.x(), pt.y());
    m_rectangle = QRectF(m_centre.x() - m_radius, m_centre.y() - m_radius, 2 * m_radius, 2 * m_radius);
    if(m_radius > 1e-2) return true;
    return false;
}

bool CircleMeasure::buildByDiameterPoints(QPointF p1, QPointF p2)
{
    m_centre = (p1 + p2) / 2.0;
    QPointF pt = p2 - m_centre;
    m_radius = hypot(pt.x(), pt.y());
    m_rectangle = QRectF(m_centre.x() - m_radius, m_centre.y() - m_radius, 2 * m_radius, 2 * m_radius);
    if(m_radius > 1e-2) return true;
    return false;
}
} //namespace Qly
